using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Common.Util;
using Dewin.BO.Actions;
using Dewin.BO.Base;
using Dewin.BO.Model;
using Dewin.BO.Util;
using Log.Controller;

namespace Dewin.BO.AgentMember
{
    /// <summary>
    /// Lop abstract de cho cac loai agent ke thua
    /// </summary>
    public class Agent : Account
    {
        #region Public Variables
        /// <summary>
        /// Loai tai khoan Agent: Sbo, Ibc...
        /// </summary>
        public string Type { get; set; }

        /// <summary>
        /// Danh sach tai khoan con
        /// </summary>
        public List<AgentMember> Members { get; set; }
        #endregion

        #region Constructor
        public Agent()
        {
            Members = new List<AgentMember>();
            IsLogin = false;
            Cookie = new CookieContainer();
        }
        #endregion

        #region Cac ham lien quan den viec quan ly tai khoan agent

        private const string Filename = "SboAgent.txt";

        /// <summary>
        /// Ham lay danh sach Agent tu file
        /// </summary>
        /// <returns></returns>
        public static List<Agent> GetAccounts()
        {
            var result = new List<Agent>();
            try
            {
                string str = IOFunctions.ReadFile(DewinConstant.PathData, Filename);

                if (!string.IsNullOrEmpty(str))
                    result = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Agent>>(str);
            }
            catch (Exception ex)
            {
                LogController.WriteLog(System.Runtime.InteropServices.Marshal.GetExceptionCode(), ex, Network.GetLocalIp());
            }
            return result;
        }

        /// <summary>
        /// Lay thong tin tai khoan agent tu file theo id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static Agent GetAccount(string id)
        {
            try
            {
                return GetAccounts().FirstOrDefault(account => account.Id == id);
            }
            catch (Exception ex)
            {
                LogController.WriteLog(System.Runtime.InteropServices.Marshal.GetExceptionCode(), ex, Network.GetLocalIp());
            }

            return null;
        }

        /// <summary>
        /// Ham ghi account
        /// </summary>
        /// <param name="agent"></param>
        /// <returns></returns>
        public static bool Save(Agent agent)
        {
            try
            {
                // Lay danh sach account tu file
                var list = GetAccounts();

                // Neu Agent Id chua co thi khoi tao Id moi
                if (string.IsNullOrEmpty(agent.Id))
                {
                    if (!BuildNewId(agent, list)) return false;
                }

                // Set lai domain cho phu hop
                // Ex: http://agent.sbo55.com => http://agent.sbo55.com/
                agent.Address = agent.Address.EndsWith("/") ? agent.Address : agent.Address + "/";

                // Khoi tao danh sach moi
                list = new List<Agent> { agent };

                // Luu list
                return Save(list);
            }
            catch (Exception ex)
            {
                LogController.WriteLog(System.Runtime.InteropServices.Marshal.GetExceptionCode(), ex, Network.GetLocalIp());
            }
            return false;
        }

        /// <summary>
        /// Ham ghi danh sach account
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public static bool Save(List<Agent> list)
        {
            try
            {
                // Thuc hien luu Address neu co domain moi
                var listDomain = list.Select(agent => new Domain
                    {
                        Address = agent.Address,
                        Side = Side.Agent,
                        Type = agent.Type
                    }).Distinct().ToList();
                Domain.Save(listDomain);

                // Lay danh sach agent tu file
                var allList = GetAccounts();

                // Xoa cac domain trong list cu ma ton tai trong list moi
                allList.RemoveAll(
                    agent => list.Exists(agent2 => agent.Id == agent2.Id));

                // Add list moi vao
                allList.AddRange(list);

                string strData = Newtonsoft.Json.JsonConvert.SerializeObject(allList.Select(agent => new
                    {
                        agent.Id,
                        agent.Username,
                        agent.Password,
                        agent.Address,
                        agent.Type,
                        Members = agent.Members.Select(member => new { member.Username, member.Settings }).ToList()
                    }));
                return IOFunctions.WriteFile(strData, DewinConstant.PathData, Filename);
            }
            catch (Exception ex)
            {
                LogController.WriteLog(System.Runtime.InteropServices.Marshal.GetExceptionCode(), ex, Network.GetLocalIp());
            }

            return false;
        }

        /// <summary>
        /// Ham tao Id moi
        /// </summary>
        /// <param name="agent"></param>
        /// <param name="agents"></param>
        /// <returns></returns>
        private static bool BuildNewId(Agent agent, List<Agent> agents)
        {
            try
            {
                // Neu so tai khoan agent da du thi khong tao nua
                if (agents.Count > DewinConstant.LimitAgentCount) return false;

                // Hien tai gioi han so agent la 10
                for (int i = 0; i < DewinConstant.LimitAgentCount; i++)
                {
                    // Tao Id
                    var id = String.Format(Provider.IdStructure, Side.Agent, agent.Type, i + 1);

                    // Neu agent chua co Id thi them va tra ve true
                    if (!agents.Exists(x => x.Id == id))
                    {
                        agent.Id = id;
                        return true;
                    }
                }
            }
            catch (Exception ex)
            {
                LogController.WriteLog(System.Runtime.InteropServices.Marshal.GetExceptionCode(), ex, Network.GetLocalIp());
            }
            return false;
        }
        #endregion

        #region Virtual Methods
        /// <summary>
        /// Dinh nghia 1 delegate de callback
        /// </summary>
        /// <returns></returns>
        private delegate object CallbackMethod(Agent agent);

        /// <summary>
        /// Ham phan ra theo loai agent va goi theo action truyen vao
        /// </summary>
        /// <param name="sboAction"></param>
        private object SwitchType(CallbackMethod sboAction)
        {
            try
            {
                switch (Type)
                {
                    case Provider.Sbo:
                        return sboAction(this);
                }
            }
            catch (Exception ex)
            {
                LogController.WriteLog(System.Runtime.InteropServices.Marshal.GetExceptionCode(), ex, Network.GetLocalIp());
            }
            return null;
        }

        /// <summary>
        /// Bat dau chay agent
        /// </summary>
        public void Start()
        {
            SwitchType(ActionFactory.SboAgentAction.Start);
        }

        /// <summary>
        /// Thuc hien Login
        /// </summary>
        /// <returns></returns>
        public virtual bool Login()
        {
            var result = SwitchType(ActionFactory.SboAgentAction.Login);
            return result != null && (bool) result;
        }

        /// <summary>
        /// Thuc hien Logout
        /// </summary>
        /// <returns></returns>
        public virtual bool Logout()
        {
            var result = SwitchType(ActionFactory.SboAgentAction.Logout);
            return result != null && (bool)result;
        }

        /// <summary>
        /// Kiem tra Logout
        /// </summary>
        /// <returns></returns>
        public virtual bool CheckLogout()
        {
            var result = SwitchType(ActionFactory.SboAgentAction.CheckLogout);
            return result != null && (bool)result;
        }

        #endregion
    }
}
